#include "stdafx.h"
#include "Logger.h"
#include <mutex>
#include <fstream>
#include <conio.h>
#include <stdarg.h>
#include <memory>

static std::string g_logfile = "./logger.log";
static std::mutex g_mutex;
static std::fstream g_fstream;

Logger::Logger()
{
}

Logger::~Logger()
{
}

int32_t Logger::Init(const std::string& logfile)
{
	std::lock_guard<std::mutex> lock(g_mutex);
	if (!logfile.empty())
	{
		g_logfile = logfile;
	}
	return 0;
}

int32_t Logger::Release()
{
	try
	{
		if (g_fstream.is_open())
		{
			g_fstream.close();
		}
	}
	catch (...) { }
	return 0;
}

void Logger::Log(const LOG_LEVEL level, char* func, const int32_t line, const char* module, int32_t error, char* format, ...)
{
	std::lock_guard<std::mutex> lock(g_mutex);
	if (g_logfile.empty())
	{
		return;
	}

	std::string strLogLevel = "";
	switch (level)
	{
	case LOG_LEVEL_DEBUG:
		strLogLevel = "DEBUG";
		break;
	case LOG_LEVEL_WARNING:
		strLogLevel = "WARNING";
		break;
	case LOG_LEVEL_ERROR:
		strLogLevel = "ERROR";
		break;
	default:
		strLogLevel = "UNKOWN";
		break;
	}

	::time_t now;
	::time(&now);
	::tm local;
	if (0 != _localtime64_s(&local, &now))
	{
		return;
	}

	DWORD threadId = ::GetCurrentThreadId();

	// [2017/09/22 16:18:00] [level] [module] [function line] [error]
	int32_t count = _scprintf("[%04d/%02d/%02d %02d:%02d:%02d] [%s] [%s] [%s,%d] [%d] [%d] ",
		local.tm_year + 1990, local.tm_mon + 1, local.tm_mday,
		local.tm_hour, local.tm_min, local.tm_sec,
		strLogLevel.c_str(),
		module,
		func, line, threadId, error);
	if (count <= 0)
	{
		return;
	}
	count += 1;
	std::auto_ptr<char> buf(new (std::nothrow)char[count]);
	if (nullptr == buf.get())
	{
		return;
	}
	if (count <= snprintf(buf.get(), count, "[%04d/%02d/%02d %02d:%02d:%02d] [%s] [%s] [%s,%d] [%d] [%d] ",
		local.tm_year + 1990, local.tm_mon + 1, local.tm_mday,
		local.tm_hour, local.tm_min, local.tm_sec,
		strLogLevel.c_str(),
		module,
		func, line, threadId, error))
	{
		return;
	}

	std::string strFormat = buf.get();
	strFormat += format;
	strFormat += "\n";

	va_list args;
	va_start(args, format);
	count = _vscprintf(strFormat.c_str(), args);
	//va_end(args);
	if (count <= 0)
	{
		return;
	}
	count += 1;
	buf.reset(new (std::nothrow)char[count]);
	if (nullptr == buf.get())
	{
		return;
	}
	if (count <= vsprintf_s(buf.get(), count, strFormat.c_str(), args))
	{
		return;
	}

	try
	{
		if (!g_fstream.is_open())
		{
			g_fstream.open(g_logfile.c_str(), std::ios::app|std::ios::in);
		}
		g_fstream << buf.get();
		g_fstream.flush();
	}
	catch (...) { }
}
